package ssl

import (
	"os"
	"strings"
	"time"

	"github.com/istower/ssl_cert_auto/dns"
	"github.com/istower/ssl_cert_auto/utils"
)

const (
	ProduceCode  = "symantec-free-1-free"
	ValidateType = "DNS"
)

var OrderChan chan *CertificateInfo

func Operator(certificateInfo *CertificateInfo) {
	utils.Log.Infof("开始执行任务， 域名：%s, 路径: %s", certificateInfo.Domain, certificateInfo.StorePath)
	OrderChan = make(chan *CertificateInfo, 5)
	res, err := certificateInfo.CreateCertificate()
	if err != nil || *res.StatusCode != 200 {
		utils.Log.Errorf("生成证书失败,错误信息: %s", err)
		return
	}
	utils.Log.Info("证书申请已经成功提交")
	time.Sleep(time.Millisecond * 500)

	orderId := *res.Body.OrderId
	certificateInfo.OrderID = orderId
	OrderChan <- certificateInfo

	state, err := certificateInfo.DescribeCertificateState()
	if err != nil || *state.StatusCode != 200 {
		utils.Log.Errorf("获取证书域名验证参数失败,错误信息: %s", err)
		return
	}
	utils.Log.Info("获取证书对应的域名校验信息完成")
	fullDomain := strings.Split(*state.Body.RecordDomain, ".")
	rr := strings.Join(fullDomain[:2], ".")
	domain := strings.Join(fullDomain[2:], ".")
	dnsEntry := dns.NewDnsEntry("en", "127.0.0.1", domain, rr, *state.Body.RecordType, *state.Body.RecordValue, 600, "default")

	response, err := dnsEntry.CreateDnsEntry()
	if err != nil {
		utils.Log.Errorf("添加dns记录失败,错误信息: %s", err)
		return
	}
	if *response.StatusCode != 200 {
		utils.Log.Errorln(response.Body)
	} else {
		utils.Log.Info("添加dns记录完成")
	}
	select {
	case ci := <-OrderChan:
		//审核需要时间，这里暂停2分钟
		utils.Log.Infof("开始轮询证书审核结果(2分钟), 当前证书对应域名: %s", ci.Domain)
		time.Sleep(time.Minute * 2)
		state, err2 := ci.DescribeCertificateState()
		if err2 != nil || *state.StatusCode != 200 {
			utils.Log.Errorf("获取证书签发信息失败, 错误信息: %s", err)
			//失败了进行重试,只有三次重试机会
			if ci.Times <= 2 {
				ci.Times += 1
				OrderChan <- certificateInfo
			}
			//失败的情况应该有消息提醒
		}
		if *state.Body.Type != "certificate" {
			//获取到正常数据，但是数据类型不是certificate，说明还没有签发完成，再次重试
			if ci.Times <= 2 {
				ci.Times += 1
				OrderChan <- certificateInfo
			}
			//失败的情况应该有消息提醒
		} else {
			key := *state.Body.PrivateKey
			pem := *state.Body.Certificate
			err = writeCertificate(ci, key, "key")
			err1 := writeCertificate(ci, pem, "pem")
			if err != nil || err1 != nil {
				if ci.Times <= 2 {
					ci.Times += 1
					OrderChan <- certificateInfo
				}
			} else {
				//正常结束，退出goroutine
				utils.Log.Infof("证书已经通过申请，并且保存在目录 <%s> 中", ci.StorePath)
				return
			}
		}
	default:
		utils.Log.Info("等待证书审核")
	}
}

func writeCertificate(ci *CertificateInfo, info, certType string) error {
	path := ci.StorePath + "/" + ci.Domain + "."
	switch certType {
	case "pem":
		path = path + "pem"
	case "key":
		path = path + "key"
	}

	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		utils.Log.Errorf("打开数据文件失败，错误信息: %s", err)
		return err
	}
	_, err = file.WriteString(info)
	if err != nil {
		utils.Log.Errorf("写入数据到文件失败，错误信息: %s", err)
		return err
	}
	return nil
}
